/*
 * Copyright (C) 2013 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.common.collect;

import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;

/**
 * This class implements the GWT serialization of {@link Range}.
 * 
 * @author Ian Springer
 */
public class Range_CustomFieldSerializer {
    public static void serialize(SerializationStreamWriter streamWriter, Range range)
            throws SerializationException {
        streamWriter.writeBoolean(range.hasLowerBound());
        if (range.hasLowerBound()) {
            streamWriter.writeObject(range.lowerEndpoint());
            streamWriter.writeBoolean(range.lowerBoundType() == BoundType.CLOSED);
        }
        streamWriter.writeBoolean(range.hasUpperBound());
        if (range.hasUpperBound()) {
            streamWriter.writeObject(range.upperEndpoint());
            streamWriter.writeBoolean(range.upperBoundType() == BoundType.CLOSED);
        }
    }

    public static Range instantiate(SerializationStreamReader streamReader)
            throws SerializationException {
        Comparable lowerEndpoint = null;
        BoundType lowerBoundType = null;
        boolean hasLowerBound = streamReader.readBoolean();
        if (hasLowerBound) {
            lowerEndpoint = (Comparable) streamReader.readObject();
            if (lowerEndpoint == null) {
                throw new SerializationException("Lower endpoint was null");
            }
            boolean inclusive = streamReader.readBoolean();
            lowerBoundType = BoundType.forBoolean(inclusive);
        }

        Comparable upperEndpoint = null;
        BoundType upperBoundType = null;
        boolean hasUpperBound = streamReader.readBoolean();
        if (hasUpperBound) {
            upperEndpoint = (Comparable) streamReader.readObject();
            if (upperEndpoint == null) {
                throw new SerializationException("Upper endpoint was null");
            }
            boolean inclusive = streamReader.readBoolean();
            upperBoundType = BoundType.forBoolean(inclusive);
        }

        Range range;
        if (hasLowerBound && hasUpperBound) {
            if (lowerEndpoint.getClass() != upperEndpoint.getClass()) {
                throw new SerializationException("Endpoint types are not the same - lower endpoint deserialized to ["
                                                         + lowerEndpoint.getClass().getName()
                                                         + "], and upper endpoint deserialized to ["
                                                         + upperEndpoint.getClass().getName() + "].");
            }
            range = Range.range(lowerEndpoint, lowerBoundType, upperEndpoint, upperBoundType);
        } else if (hasLowerBound) {
            range = Range.downTo(lowerEndpoint, lowerBoundType);
        } else if (hasUpperBound) {
            range = Range.upTo(upperEndpoint, upperBoundType);
        } else {
            range = Range.all();
        }
        return range;
    }

    @SuppressWarnings("UnusedParameters")
    public static void deserialize(SerializationStreamReader streamReader, Range range)
            throws SerializationException {
        // intentionally empty, as instantiate() handles deserialization
    }
}
